package com.sec.android.app.myfiles.module.sfinder;

import android.Manifest;
import android.app.SearchManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.support.v4.content.ContextCompat;
import android.text.format.Formatter;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.info.MediaFile;
import com.sec.android.app.myfiles.info.MimeType;
import com.sec.android.app.myfiles.module.abstraction.AbsMediaProviderImp;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;
import com.sec.android.app.myfiles.module.abstraction.FileRecord.StorageType;
import com.sec.android.app.myfiles.module.local.file.LocalFileRecord;
import com.sec.android.app.myfiles.provider.DbTableInfo;
import com.sec.android.app.myfiles.provider.DbTableInfo.COLUMN_ID;
import com.sec.android.app.myfiles.util.FileUtils;
import com.sec.android.app.myfiles.util.PreferenceUtils;
import com.sec.android.app.myfiles.util.SemFwWrapper;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SFinderProviderImp extends AbsMediaProviderImp {
    private static final String FILE_NAME_FIND_FILTER = "\"abcdefghijklmnopqrstuvwxyz01234567890;[] .!@#$%^&()-_=+\"";
    private static final String RESOURCE_URI_PREFIX = "android.resource://com.sec.android.app.myfiles/";
    private static final String DOCUMENT_FILTER = "searchfilter=document";
    private static final String DOCUMENT_QUERY = "is_doc=1";

    private static final String REGEX_BLOCK_START_END = "\\[([^\\[]+)\\]";
    private static final String REGEX_START_END = "^\\[|\\]$";
    private static final int QUERY_PARSER_VERSION = 1;
    private static final Pattern PATTERN_BLOCK_START_END = Pattern.compile(REGEX_BLOCK_START_END);
    private static final Pattern PATTERN_START_END = Pattern.compile(REGEX_START_END);

    private final DbTableInfo mColumnInfo;

    private int pathIndex = -1;
    private int dateIndex = -1;
    private int sizeIndex = -1;
    private int mimeIndex = -1;

    public SFinderProviderImp(Context context) {
        super(context);

        mColumnInfo = DbTableInfo.getInstance(getStorage());

        pathIndex = mColumnInfo.getIndex(COLUMN_ID.PATH);
        dateIndex = mColumnInfo.getIndex(COLUMN_ID.DATE);
        sizeIndex = mColumnInfo.getIndex(COLUMN_ID.SIZE);
        mimeIndex = mColumnInfo.getIndex(COLUMN_ID.MIME_TYPE);
    }

    @Override
    protected StorageType getStorage() {
        return StorageType.S_Finder;
    }

    private String makeTimeQuery(String query, String sTime, String eTime) {
        String ret = query;

        String timeCol = mColumnInfo.getColumnName(COLUMN_ID.DATE);

        if (sTime != null && eTime != null) {
            Long startTime = Long.parseLong(sTime) / 1000;
            Long endTime = Long.parseLong(eTime) / 1000;

            StringBuilder sb = new StringBuilder();

            sb.append(" ( ");
            sb.append(timeCol);
            sb.append(" BETWEEN ");
            sb.append(startTime);
            sb.append(" and ");
            sb.append(endTime);
            sb.append(" ) ");

            ret = addQuery(query, sb.toString());
        }

        return ret;
    }

    private String makeShowHiddenQuery(String query) {
        String ret = query;

        String pathCol = mColumnInfo.getColumnName(COLUMN_ID.PATH);
        String noSearchHiddenFile = pathCol + " NOT LIKE '%/.%'";

        if (!showHidden()) {
            ret = addQuery(query, noSearchHiddenFile);
        }

        return ret;
    }

    private String addQuery(String query, String add) {
        StringBuilder sb = new StringBuilder();

        if (query != null) {
            sb.append(query);
            sb.append("AND ( ");
            sb.append(add);
            sb.append(" ) ");
        } else {
            sb.append(" ( ");
            sb.append(add);
            sb.append(" ) ");
        }

        return sb.toString();

    }

    @Override
    protected Cursor _query(Uri uri, String[] projectionIn, String selection, String[] selectionArgs, String sortOrder) {
        if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            return null;
        }

        String limit = uri.getQueryParameter("limit");
        String[] selectList = null;
        ArrayList<String> selections = new ArrayList<>();

        String idCol = mColumnInfo.getColumnName(COLUMN_ID.ID);
        String pathCol = mColumnInfo.getColumnName(COLUMN_ID.PATH);
        String nameCol = mColumnInfo.getColumnName(COLUMN_ID.NAME);

        if (limit != null) {
            if (sortOrder != null) {
                sortOrder += " limit " + limit;
            } else {
                sortOrder = idCol + " asc limit " + limit;
            }
        }

        if (selectionArgs != null) {
            selectList = regexParser(selectionArgs[0]);
        }

        String dataParser = "(SUBSTR(LOWER(" + pathCol + "),LENGTH(RTRIM(LOWER(" + pathCol + ")," + FILE_NAME_FIND_FILTER + "))) LIKE ? ) "
                + "OR (" + nameCol + " LIKE ? )";

        String sTime = uri.getQueryParameter("stime");
        String eTime = uri.getQueryParameter("etime");

        String query = makeTimeQuery(null, sTime, eTime);

        if (selectList != null) {
            for (int i = 0; i < selectList.length; i++) {
                if (i % 2 == 0) {
                    query = addQuery(query, dataParser);
                    selections.add("%" + selectList[i] + "%");
                    selections.add("%" + selectList[i] + "%");
                }
            }
        }

        query = makeShowHiddenQuery(query);

        String uriString = uri.toString();
        if (uriString.contains(DOCUMENT_FILTER)) {
            query = addQuery(query, DOCUMENT_QUERY);
        }

        String args[] = null;
        int size = selections.size();
        if (size > 0) {
            args = selections.toArray(new String[size]);
        }

        MatrixCursor ret = null;
        try (Cursor myFileCursor = super._query(FileUtils.MEDIA_PROVIDER_URI, mColumnInfo.getProjection(), query, args, sortOrder)) {
            if (myFileCursor != null && myFileCursor.getCount() > 0) {
                ret = (MatrixCursor) getSearchCursor(myFileCursor);
            }
        }

        return ret;
    }

    private boolean showHidden() {
        return PreferenceUtils.getShowHiddenFiles(mContext);
    }

    private static String[] regexParser(String str) {
        if (QUERY_PARSER_VERSION == 1) {
            List<String> resultList = new ArrayList<>();
            Matcher matcher = PATTERN_BLOCK_START_END.matcher(str);
            String tmpString;

            while (matcher.find()) {
                tmpString = matcher.group();
                tmpString = PATTERN_START_END.matcher(tmpString).replaceAll("");
                resultList.add(tmpString);
            }
            return resultList.toArray(new String[resultList.size()]);
        } else {
            return str.split("\n");
        }
    }

    private Uri getFileIconUri(String fullPath) {
        int resId = MediaFile.getIcon(fullPath, mContext);
        return Uri.parse(RESOURCE_URI_PREFIX + resId);
    }

    private Uri getFolderIconUri() {
        return Uri.parse(RESOURCE_URI_PREFIX + R.drawable.myfiles_list_folder_tint);
    }

    private Cursor getSearchCursor(Cursor cursor) {
        MatrixCursor ret = new MatrixCursor(new String[]{
                SearchManager.SUGGEST_COLUMN_ICON_1, SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_TEXT_2,
                SearchManager.SUGGEST_COLUMN_INTENT_DATA,
                SearchManager.SUGGEST_COLUMN_ICON_2
        });

        Uri fileIconUri;
        String fileName;
        long date;
        String fileSize;
        String folder_capacity = "-1";
        String filePath;
        Uri contentUri;
        String mimeType;
        String targetType;
        Uri uri;
        boolean showHidden = PreferenceUtils.getShowHiddenFiles(mContext);

        cursor.moveToFirst();

        do {
            filePath = cursor.getString(pathIndex);
            fileSize = null;
            uri = null;
            contentUri = null;

            if (filePath != null) {
                fileName = FileRecord.getName(filePath);

                date = cursor.getLong(dateIndex) * 1000;

                mimeType = cursor.getString(mimeIndex);

                if (SemFwWrapper.file(filePath).isDirectory()) {
                    targetType = "1";
                    int childCounts[] = LocalFileRecord.getChildFileCount(SemFwWrapper.file(filePath));
                    int childCount = childCounts[LocalFileRecord.WITHOUT_HIDDEN];
                    if (showHidden) {
                        childCount = childCounts[LocalFileRecord.WITH_HIDDEN];
                    }

                    folder_capacity = String.valueOf(childCount);
                    fileIconUri = getFolderIconUri();
                } else {
                    targetType = "0";

                    fileSize = Formatter.formatShortFileSize(mContext, cursor.getLong(sizeIndex));
                    fileIconUri = getFileIconUri(filePath);

                    if (SemFwWrapper.file(filePath).exists()) {
                        uri = Uri.fromFile(SemFwWrapper.file(filePath));
                    }

                    contentUri = FileUtils.getUriByPath(mContext, filePath);
                    if (contentUri == null) {
                        contentUri = uri;
                    }

                    mimeType = cursor.getString(mimeIndex);
                    // if there is no mime type in DB
                    if (mimeType == null) {
                        mimeType = MediaFile.getMimeType(filePath);
                    } else if (mimeType.equalsIgnoreCase(MimeType.MSOFFICE_PPT_GOOGLE)) {
                        mimeType = MimeType.MSOFFICE_PPT_MS;
                    }
                }

                Object[] column = new Object[]{
                        fileIconUri, fileName, date, fileSize, folder_capacity, filePath, contentUri, mimeType, targetType, uri};

                ret.addRow(column);
            }
        } while (cursor.moveToNext());

        return ret;
    }
}
